/*内核模块程序——阻塞IO*/

/*

//add k1																									
key1_button {																									
	compatible = "rk3399,key1-button";																								
	gpios1 = <&gpio1 1 IRQ_TYPE_EDGE_BOTH>; //GPIO1_A1																								
	gpios2 = <&gpio1 3 IRQ_TYPE_EDGE_BOTH>; //GPIO1_A3																								
	gpios3 = <&gpio1 4 IRQ_TYPE_EDGE_BOTH>; //GPIO1_A4																								
	pinctrl-names = "default";																								
	pinctrl-0 = <&button_k1_gpio>;																								
};																									

&pinctrl {																									
	key1_button {																								
		button_k1_gpio:button_k1_gpio {																							
			rockchip,pins = <1 1 RK_FUNC_GPIO &pcfg_pull_up>,																						
			<1 3 RK_FUNC_GPIO &pcfg_pull_up>,																						
			<1 4 RK_FUNC_GPIO &pcfg_pull_up>;																						
		};																							
	};																								
	...																								
};

*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <dt-bindings/gpio/gpio.h>

#include "button.h"


/*定义结构体类型*/
struct rk3399_button
{
	unsigned int major;
	struct class* pcls;
	struct device* pdev;
	unsigned int gpio;//引脚号
	int irq;//中断号
	int value;//按键引脚当前电平状态
	int validvalue;//按键引脚有效电平
	struct BUTTON button;
	wait_queue_head_t wqhead;
	int condition;
};

/*全局变量*/
static struct rk3399_button* pbutton;//声明结构体指针，但没分配结构体变量空间

//定义id_table表
static const struct platform_device_id button_id_table[] = 
{
	{ .name = "rk3399_button", .driver_data = 0x1 }, 
	{ .name = "rk3288_button", .driver_data = 0x2 }, 
	{ .name = "rk3568_button", .driver_data = 0x3 },
};

//定义compatible匹配表
static const struct of_device_id button_match[] = 
{
	{ .compatible = "rk3399,power-button", },
};


/*中断处理函数*/
static irqreturn_t button_handler(int irq, void *dev_id)
{
	int value;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*读取GPIO口电平状态*/
	pbutton->button.code = 'A';
	value = gpio_get_value(pbutton->gpio);
	if(value == pbutton->validvalue)//如果当前IO口电平为有效电平
		pbutton->button.value = 1;//1表示按下状态
	else
		pbutton->button.value = 0;//0表示松开状态

	/*唤醒休眠进程*/
	pbutton->condition = 1;
	wake_up_interruptible(&pbutton->wqhead);
	
	return IRQ_HANDLED;
}

/*定义系统调用接口*/
static int button_open (struct inode *inode, struct file *filp)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return 0;
}

static int button_close (struct inode *inode, struct file *filp)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return 0;
}

static ssize_t button_read(struct file *filp, char __user *buf, size_t size, loff_t *flag)
{
	int ret;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*阻塞，直到条件成立——按钮按下或松开*/
	wait_event_interruptible(pbutton->wqhead,pbutton->condition);

	/*把按键状态拷贝到用户空间*/
	ret = copy_to_user(buf, &pbutton->button, sizeof(struct BUTTON));
	if(ret > 0)
	{
		printk("<kernel>copy_to_user fail.\n");
		return -EFAULT;
	}	

	/*重置按键信息和条件变量*/
	pbutton->button.code = 'X';
	pbutton->condition = 0;
	
	return sizeof(struct BUTTON);
}

static ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *flag)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);

	return size;
}

/*改变系统调用接口地址*/
static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = button_open,
	.release = button_close,
	.read = button_read,
	.write = button_write,
};

/*定义probe、remove函数*/
static int button_probe(struct platform_device *pdev)
{
	int ret;
	enum of_gpio_flags flags;
	struct device_node* pbutton_node = NULL;
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*获取平台数据*/
	pbutton_node = pdev->dev.of_node;

	/*申请分配结构体空间*/
	pbutton = kmalloc(sizeof(struct rk3399_button), GFP_KERNEL);
	if(pbutton == NULL)
	{
		printk("kmalloc fail\n");
		return -ENOMEM;
	}

	/*初始化按键信息*/
	pbutton->button.code = 'X';
	pbutton->button.value = 0;	

	/*注册主设备号（动态）*/
	pbutton->major = register_chrdev(0, "button_drv", &fops);
	if(pbutton->major < 0)
	{
		printk("<kernel>register major fail.\n");
		ret = -EBUSY;
		goto err_register_chrdev;
	}
	printk("<kernel>register major success!\n");
	printk("<kernel>major = %d\n",pbutton->major);

	/*创建设备类*/
	pbutton->pcls = class_create(THIS_MODULE, "button_cls");
	if (IS_ERR(pbutton->pcls))
	{
		ret = PTR_ERR(pbutton->pcls);
		goto err_class_create;
	}

	/*创建设备文件*/
	pbutton->pdev = device_create(pbutton->pcls,NULL, MKDEV(pbutton->major, 123),NULL,"button");
	if (IS_ERR(pbutton->pdev))
	{
		ret = PTR_ERR(pbutton->pdev);
		goto err_device_create;
	} 


	/*初始化硬件*/
	pbutton->gpio = of_get_named_gpio_flags(pbutton_node, "gpios", 0, &flags);
	if (gpio_is_valid(pbutton->gpio)) //如果获取到的引脚号是有效的
	{
		printk("<kernel>Get gpio of button success!\n");
		printk("<kernel>gpio_button = %d\n", pbutton->gpio);
		if(flags == GPIO_ACTIVE_LOW)
		{
			printk("<kernel>Low is valid.\n");
			pbutton->validvalue = 0;
		}
		else
		{
			printk("<kernel>High is valid.\n");
			pbutton->validvalue = 1;
		}
	} 
	else 
	{
		printk("<kernel>of_get_named_gpio_flags fail.\n");
		return -EFAULT;
	}	
	
	gpio_request(pbutton->gpio, pbutton_node->name);
	gpio_direction_input(pbutton->gpio);//将按键IO口设置为输入方向
	gpio_free(pbutton->gpio);

	/*获取中断号*/
	pbutton->irq = gpio_to_irq(pbutton->gpio);
	printk("<kernel>irq:%d\n",pbutton->irq);

	/*申请中断*/
	ret = request_irq(pbutton->irq, button_handler, IRQ_TYPE_EDGE_BOTH, 
			"pwr_interrupt", NULL);//双边沿都能触发中断
	if (ret < 0) 
	{
		printk("request_irq fail\n");
		ret = -EINVAL;
		goto err_request_irq;
	} 

	/*初始化等待队列头*/
	init_waitqueue_head(&pbutton->wqhead);
	pbutton->condition = 0;//初始时默认条件不成立

	return 0;

	/*集中容错处理*/
err_request_irq:
	device_destroy(pbutton->pcls, MKDEV(pbutton->major, 123));
err_device_create:
	class_destroy(pbutton->pcls);
err_class_create:
	unregister_chrdev(pbutton->major, "button_drv");
err_register_chrdev:
	kfree(pbutton); 

	return ret;
}

static int button_remove(struct platform_device *pdev)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);

	/*释放中断*/
	free_irq(pbutton->irq, NULL);

	/*销毁设备文件*/
	device_destroy(pbutton->pcls, MKDEV(pbutton->major, 123));

	/*销毁设备类*/
	class_destroy(pbutton->pcls);
	
	/*注销主设备号*/
	unregister_chrdev(pbutton->major, "button_drv");
	printk("<kernel>unregister major success!\n");

	/*释放堆区空间*/
	kfree(pbutton);

	return 0;
}


/*定义平台驱动对象*/	
static struct platform_driver button_driver = 
{
	.probe		= button_probe,
	.remove		= button_remove,
	.driver		= {.name	= "rk_button", .of_match_table = button_match,},
	.id_table	= button_id_table,
};


/*入口函数——insmod调用*/
static int __init driver_mod_init(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	return platform_driver_register(&button_driver);
}

/*出口函数——rmmod调用*/
static void __exit driver_mod_exit(void)
{
	printk("<kernel>call function:%s\n",__FUNCTION__);
	platform_driver_unregister(&button_driver);
}


module_init(driver_mod_init); //告诉内核本模块程序的入口函数名
module_exit(driver_mod_exit);//告诉内核本模块程序的出口函数名
MODULE_LICENSE("GPL"); //遵守开源许可协议



